#include <iostream>
#include <float.h>
#include <math.h>
#include "Interval.h"
#include "MultiInterval.h"

using namespace std;

class IA {
	
};
Interval::Interval(double a, double b) {
	this->set(a,b);
}
Interval& Interval::Create(double a, double b) {
	return *new Interval(a,b);
}
Interval& Interval::set(double a, double b) {
	if (a>b)
		this->a=b,
		this->b=a;
	else
		this->a=a,
		this->b=b;
	return *this;
}
Interval& Interval::set(double a) {
	this->a=this->b=a;
	return *this;
}
Interval& Interval::set(const Interval& a) {
	this->a=a.a;
	this->b=a.b;
	return *this;
}
Interval& Interval::operator+=(double d) {
	this->a+=d;
	this->b+=d;
	return *this;
}
Interval& Interval::operator-=(double d) {
	this->a-=d;
	this->b-=d;
	return *this;
}
Interval& Interval::operator*=(double d) {
	return set(a*d,b*d);
}
Interval& Interval::operator/=(double d) {
	return set(a/d,b/d);
}
Interval& Interval::operator+=(const Interval& d) {
	this->set(a+d.a, b+d.b);
	return *this;
}
Interval& Interval::operator-=(const Interval& d) {
	this->set(a-d.a, b-d.b);
	return *this;
}
Interval& Interval::operator*=(const Interval& d) {
	FourMM(a*d.a,a*d.b,b*d.a,b*d.b,this->a,this->b);
	return *this;
}
Interval& Interval::operator/=(const Interval& d) {
	FourMM(a/d.a,a/d.b,b/d.a,b/d.b,this->a,this->b);
	return *this;
}
Interval Interval::operator+(double d) {
	Interval a = *this;
	return a+=d;
}
Interval Interval::operator-(double d) {
	Interval a = *this;
	return a-=d;
}
Interval Interval::operator*(double d) {
	Interval a = *this;
	return a*=d;
}
Interval Interval::operator/(double d) {
	Interval a = *this;
	return a/=d;
}
Interval Interval::operator+(const Interval& d) {
	Interval a = *this;
	return a+=d;
}
Interval Interval::operator-(const Interval& d) {
	Interval a = *this;
	return a-=d;
}
Interval Interval::operator*(const Interval& d) {
	Interval a = *this;
	return a*=d;
}
Interval Interval::operator/(const Interval& d) {
	Interval a = *this;
	return a/=d;
}
Interval& Interval::_sin() {
	if (b-a >= M_PI*2)
		return this->set(-1,1);
	int q1 = ::abs((int) floor(a / M_PI - 0.5)), q2 = ::abs((int) floor(b / M_PI - 0.5));
	bool s1 = q1 % 2 == 0, s2 = q2 % 2 == 0;
	if (s1) {
		if (s2) {
			if (::abs(q1 - q2) >= 1)
				return this->set(-1, 1);
			else
				return this->set(::sin(a), ::sin(b));
		}
		return this->set(-1, max(::sin(a), ::sin(b)));
	} else {
		if (s2)
			return this->set(min(::sin(a), ::sin(b)), 1);
		if (::abs(q1 - q2) >= 1)
			return this->set(-1, 1);
		else
			return this->set(::sin(a), ::sin(b));
	}
}
Interval& Interval::_cos() {
	if (b-a >= M_PI*2)
		return this->set(-1,1);
	int q1 = ::abs((int) floor(a / M_PI)), q2 = ::abs((int) floor(b / M_PI));
	bool s1 = q1 % 2 == 0, s2 = q2 % 2 == 0;
	if (s1) {
		if (s2) {
			if (::abs(q1 - q2) >= 1)
				return this->set(-1, 1);
			else
				return this->set(::cos(a), ::cos(b));
		}
		return this->set(-1, max(::cos(a), ::cos(b)));
	} else {
		if (s2)
			return this->set(min(::cos(a), ::cos(b)), 1);
		if (::abs(q1 - q2) >= 1)
			return this->set(-1, 1);
		else
			return this->set(::cos(a), ::cos(b));
	}
}
Interval& Interval::_abs() {
	if ((a < 0 && b > 0) || (a > 0 && b < 0))
		return set(0, max(::abs(a), ::abs(b)));
	return set(::abs(a), ::abs(b));
}
Interval& Interval::_negative() {
	return set(-a, -b);
}
Interval& Interval::operator^=(double q) {
	if (q == 0)
		return set(1);
	double pa = ::pow(a, q), pb = ::pow(b, q);
	if (_isnan(pa) || _isnan(pb))
		return set(::NAN);
	if (a < 0 && b > 0)
		return set(0, ::max(pa, pb));
	return set(pa, pb);
}
Interval Interval::operator^(double q) {
	Interval a = *this;
	return a^=q;
}
bool Interval::contains(double value) {
	return value >= a && value <= b;
}
Interval& Interval::operator%=(double x) {
	double xd = nexttoward(x, NEG_INF);
	if (b - a >= x)
		return set(0, xd);
	int aa = (int) (a / x), bb = (int) (b / x);
	if (aa == bb)
		return set(a - aa * x, b - bb * x);
	return set(0, xd);
}
Interval Interval::operator%(double q) {
	Interval a = *this;
	return a%=q;
}
Interval Interval::sin() {
	Interval a = *this;
	return a._sin();
}
Interval Interval::cos() {
	Interval a = *this;
	return a._cos();
}
Interval Interval::abs() {
	Interval a = *this;
	return a._abs();
}
Interval Interval::negative() {
	Interval a = *this;
	return a._negative();
}
void Interval::FourMM(double a, double b, double c, double d, double& mmin, double& mmax) {
	mmin=DBL_MAX, mmax=DBL_MIN;
	if (a > mmax) mmax = a;
	if (a < mmin) mmin = a;
	if (b > mmax) mmax = b;
	if (b < mmin) mmin = b;
	if (c > mmax) mmax = c;
	if (c < mmin) mmin = c;
	if (d > mmax) mmax = d;
	if (d < mmin) mmin = d;
}
ostream& operator <<(ostream& os, const Interval &i) {
	return os<<'['<<i.a<<','<<i.b<<']';
}
int main() {
	Interval i = Interval::Create(1,2);
	cout<<i.sin()<<endl;
	return 0;
}
